package com.zz.ai.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.SocketConfig;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * Utility Class Over HTTP
 *
 * @author pengming
 */
public class HttpUtils {
    protected final Logger log = LoggerFactory.getLogger(getClass());

    private static volatile HttpUtils instance = new HttpUtils();
    private ConnectionConfig connConfig;
    private SocketConfig socketConfig;
    private RequestConfig requestConfig;
    private PoolingHttpClientConnectionManager connManager;
    private static CloseableHttpClient httpclient;
    private static final String DEFAULT_ENCODING = "utf-8";
    static final String EMPTY_STRING = "";

    /**
     * 设置连接池的最大连接数
     **/
    private int maxTotal = 200;
    /**
     * 单条链路的最多并发数
     */
    private int maxPerRoute = maxTotal;
    /**
     * 请求超时20秒钟
     */
    private int connectTimeout = 60 * 1000;//2*1000
    /**
     * 请求sockget链接（等待数据）超时20秒钟
     */
    private int socketTimeout = 60 * 1000;//2*1000

    private HttpUtils() {
        //设置连接参数
        connConfig = ConnectionConfig.custom().setCharset(Charset.forName(DEFAULT_ENCODING)).build();
        socketConfig = SocketConfig.custom().setSoTimeout(socketTimeout).build();
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        connManager = new PoolingHttpClientConnectionManager();
        connManager.setDefaultConnectionConfig(connConfig);
        connManager.setDefaultSocketConfig(socketConfig);
        connManager.setMaxTotal(maxTotal);
        connManager.setDefaultMaxPerRoute(maxPerRoute);
        //默认每隔10秒检测一起失效链接，防止close_wait堆积
        httpclient = HttpClients.custom().evictExpiredConnections().setConnectionManager(connManager).build();
    }


    public static CloseableHttpClient getHttpclient() {
        return httpclient;
    }

    public static HttpUtils getInstance() {
        return instance;
    }

    private static List<NameValuePair> toPair(Map<String, String> params) {
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();
        Set<Entry<String, String>> paramsSet = params.entrySet();
        for (Entry<String, String> paramEntry : paramsSet) {
            pairs.add(new BasicNameValuePair(paramEntry.getKey(), paramEntry.getValue()));
        }
        return pairs;
    }

    public static String readStream(InputStream in, String encoding) throws IOException {
        if (in == null) return EMPTY_STRING;
        String enc = (encoding != null) ? encoding : DEFAULT_ENCODING;
        InputStreamReader isr = new InputStreamReader(in, enc);
        BufferedReader br = new BufferedReader(isr);
        final StringBuilder result = new StringBuilder();
        try {
            String line = null;
            while ((line = br.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException ex) {
            throw ex; //让最外层的interceptor统一捕获
        } finally {
            br.close();
            isr.close();
        }
        return result.toString();
    }

    /**
     * Post请求
     *
     * @param url
     * @param formParams
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    public HttpResponse doPost(String url, Map<String, String> formParams, Map<String, String> headerParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpPost post = new HttpPost();
        post.setConfig(requestConfig);
        URIBuilder builder = new URIBuilder(url);
        post.setURI(builder.build());
        if (formParams != null && !formParams.isEmpty()) {
            post.setEntity(new UrlEncodedFormEntity(HttpUtils.toPair(formParams), Charset.forName(DEFAULT_ENCODING)));
        }

        if (headerParams != null && !headerParams.isEmpty()) {
            for (Entry<String, String> entry : headerParams.entrySet()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }

        return httpclient.execute(post);
    }


    /**
     * Post请求
     *
     * @param url
     * @param formParams
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    public HttpResponse doPost(String url, JSONObject formParams, Map<String, String> headerParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpPost post = new HttpPost();
        post.setConfig(requestConfig);
        URIBuilder builder = new URIBuilder(url);
        post.setURI(builder.build());
        if (formParams != null && !formParams.isEmpty()) {
            StringEntity entity = new StringEntity(formParams.toString(), "utf-8");
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            post.setEntity(entity);
        }

        if (headerParams != null && !headerParams.isEmpty()) {
            for (Entry<String, String> entry : headerParams.entrySet()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }
        return httpclient.execute(post);
    }

    public HttpResponse doPost(String url, String body, Map<String, String> headerParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpPost post = new HttpPost();
        post.setConfig(requestConfig);
        URIBuilder builder = new URIBuilder(url);
        post.setURI(builder.build());
        if (body != null && !body.isEmpty()) {
            StringEntity entity = new StringEntity(body, "utf-8");
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            post.setEntity(entity);
        }

        if (headerParams != null && !headerParams.isEmpty()) {
            for (Entry<String, String> entry : headerParams.entrySet()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }
        return httpclient.execute(post);
    }

    public HttpResponse doPostHeader(String url, String body, Map<String, String> headerParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpPost post = new HttpPost();
        post.setConfig(requestConfig);
        URIBuilder builder = new URIBuilder(url);
        post.setURI(builder.build());
        if (body != null && !body.isEmpty()) {
            StringEntity entity = new StringEntity(body, "utf-8");
            post.setEntity(entity);
        }

        if (headerParams != null && !headerParams.isEmpty()) {
            for (Entry<String, String> entry : headerParams.entrySet()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }
        return httpclient.execute(post);
    }

    public InputStream doPostForStream(String url, Map<String, String> formParams, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doPost(url, formParams, headerParams);
        return response != null ? response.getEntity().getContent() : null;
    }

    public InputStream doPostForStream(String url, JSONObject formParams, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doPost(url, formParams, headerParams);
        return response != null ? response.getEntity().getContent() : null;
    }

    public InputStream doPostForStream(String url, String body, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doPost(url, body, headerParams);
        return response != null ? response.getEntity().getContent() : null;
    }

    public InputStream doPostForStreamHeader(String url, String body, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doPostHeader(url, body, headerParams);
        return response != null ? response.getEntity().getContent() : null;
    }

    public String doPostForString(String url, Map<String, String> formParams, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        return HttpUtils.readStream(this.doPostForStream(url, formParams, headerParams), null);
    }

    public String doPostForString(String url, JSONObject formParams, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        return HttpUtils.readStream(this.doPostForStream(url, formParams, headerParams), null);
    }

//    public String doPostForString(String url, String body, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
//        String uuid = UUIDUtils.getUUID();
//        try {
//            log.info(uuid+"----REQUEST:["+url+":"+JSON.parseObject(body)+"]");
//        }catch (Exception e){
//            log.info(uuid+"----REQUEST-EXCEPTION:["+url+":"+JSON.parseObject(body)+"],exception"+e);
//        }
//        String reponse = HttpUtils.readStream(this.doPostForStream(url, JSON.parseObject(body), headerParams), null);
//        try {
//            log.info(uuid+"----RESPONSE:["+url+":"+reponse+"]");
//        }catch (Exception e){
//            log.info(uuid+"----RESPONSE-EXCEPTION:["+url+":"+reponse+"],exception"+e);
//        }
//        return reponse;
//    }

    public String doPostForBodyString(String url, String body, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        return HttpUtils.readStream(this.doPostForStream(url, body, headerParams), null);
    }

//    public String doPostForBodyStringHeader(String url, String body, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
//        String uuid = UUIDUtils.getUUID();
//        try {
//            log.info(uuid+"----REQUEST:["+url+":"+JSON.parseObject(body)+"]");
//        }catch (Exception e){
//            log.info(uuid+"----REQUEST-EXCEPTION:["+url+":"+JSON.parseObject(body)+"],exception"+e);
//        }
//        String response = HttpUtils.readStream(this.doPostForStreamHeader(url, body, headerParams), null);
//        try {
//            log.info(uuid+"----RESPONSE:["+url+":"+response+"]");
//        }catch (Exception e){
//            log.info(uuid+"----RESPONSE-EXCEPTION:["+url+":"+response+"],exception"+e);
//        }
//        return response;
//    }

    /**
     * Get请求
     *
     * @param url
     * @param queryParams
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    public HttpResponse doGet(String url, Map<String, String> queryParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpGet get = new HttpGet();
        get.setConfig(requestConfig);
        URIBuilder builder = new URIBuilder(url);
        if (queryParams != null && !queryParams.isEmpty()) {
            builder.setParameters(HttpUtils.toPair(queryParams));
        }
        get.setURI(builder.build());
        return httpclient.execute(get);
    }

    /**
     * Get请求
     *
     * @param url
     * @param queryParams
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws URISyntaxException
     */
    public String doGetEx(String url, Map<String, String> queryParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpGet get = new HttpGet();
        get.setConfig(requestConfig);
        URIBuilder builder = new URIBuilder(url);
        if (queryParams != null && !queryParams.isEmpty()) {
            builder.setParameters(HttpUtils.toPair(queryParams));
        }
        get.setURI(builder.build());
        HttpResponse response = httpclient.execute(get);
        HttpEntity entity = response.getEntity();

        return EntityUtils.toString(entity, "UTF-8");
    }

    public HttpResponse doGet(String url, Map<String, String> queryParams, Map<String, String> headerParams) throws ClientProtocolException, IOException, URISyntaxException {
        HttpGet get = new HttpGet();
        get.setConfig(requestConfig);
        if (headerParams != null && !headerParams.isEmpty()) {
            for (Entry<String, String> entry : headerParams.entrySet()) {
                get.setHeader(entry.getKey(), entry.getValue());
            }
        }
        URIBuilder builder = new URIBuilder(url);
        if (queryParams != null && !queryParams.isEmpty()) {
            builder.setParameters(HttpUtils.toPair(queryParams));
        }
        get.setURI(builder.build());
        return httpclient.execute(get);
    }

    public InputStream doGet(String url) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doGet(url, null);
        return response != null ? response.getEntity().getContent() : null;
    }

    public InputStream doGetForStream(String url, Map<String, String> queryParams) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doGet(url, queryParams);
        return response != null ? response.getEntity().getContent() : null;
    }

    public InputStream doGetForStream(String url, Map<String, String> queryParams, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        HttpResponse response = this.doGet(url, queryParams, headerParams);
        return response != null ? response.getEntity().getContent() : null;
    }

    public String doGetForString(String url) throws URISyntaxException, ClientProtocolException, IOException {
        return HttpUtils.readStream(this.doGet(url), null);
    }

    public String doGetForString(String url, Map<String, String> queryParams) throws URISyntaxException, ClientProtocolException, IOException {
        return HttpUtils.readStream(this.doGetForStream(url, queryParams), null);
    }

    public String doGetForString(String url, Map<String, String> queryParams, Map<String, String> headerParams) throws URISyntaxException, ClientProtocolException, IOException {
        return HttpUtils.readStream(this.doGetForStream(url, queryParams, headerParams), null);
    }

    public static void main_(String[] args) throws ClientProtocolException, URISyntaxException, IOException {
        HttpUtils hu = HttpUtils.getInstance();
        String result = hu.doGetForString("http://localhost:8089/dps/takeout/posCommentPage?hotelGroupCode=GCBZG&hotelCode=GCBZ&type=&startPage=0&pageSize=30&pccode=110");
        System.out.println(result);
    }

}
